﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<windows.h>//Win32 API大部分都在windows库中
#include<stdlib.h>//system函数所在库
#include<stdbool.h>

//Win32API即为微软提供的控制程序行为的一些接口
//可以在cmd中作为指令直接输入，也可以在C/C++程序中使用system函数来进行调用
//注：默认启动应设置为Windows控制台主机，设置为Windows终端则无效果
//接下来，将进行部分Win32API的介绍及使用


//1.调整Windows控制台主机界面大小的mode命令及更名命令title
void test1()
{
	//将控制台主机界面大小改为100列，30行：
	system("mode con cols=100 lines=30");//mode非函数，而是cmd的一个常用于调整窗口的命令
										 //con是控制台的缩写，cols表示列，lines表示行
	
	//将控制台更名为“贪吃蛇”：
	system("title 贪吃蛇");//title为更名指令
		//设置后运行发现没有更改成功，原因是程序结束了，
		//可以使用getcher函数/pause阻止程序结束
	//getchar();//程序未终止，更名成功
	system("pause");//pause，执行后需按任意键才能继续运行程序
}

//2.定义控制台屏幕缓冲区中字符单元的坐标的结构体：COORD结构体
//坐标系 (0，0) 的原点位于缓冲区的顶部左侧单元格，x轴正方向指向右，y轴正方向指向下
//3.获得句柄的API：GetStdHandle，它用于从一个特定的标准设备（标准输入、标准输出或标
//准错误）中取得一个句柄（可以理解成屏幕缓冲区的名字，依赖句柄可以找到对应的屏幕缓冲区）
//4.获取当前句柄对应的光标信息的API：GetConsoleCursorInfo
//其第一个参数为句柄，第二个参数为光标信息结构体的指针，用以接收光标信息
//返回值为bool
//5.设置指定控制台屏幕缓冲区的光标的⼤⼩和可见性的API：SetConsoleCursorInfo
//第一个参数为句柄，第二个参数为光标信息的结构体CONSOLE_CURSOR_INFO的指针
//返回值为bool
//6.设置光标位置的API：SetConsoleCursorPosition，第一个参数为句柄，第二个参数为坐标的结构体COORD
//返回值为bool
void test2()
{
//COORD类型的声明：
//typedef struct _COORD {
//	SHORT X;
//	SHORT Y;
//} COORD, * PCOORD;
	COORD s = { 10, 20 };

	//HANDLE是句柄的类型，也就是GetStdHandle的返回值
	HANDLE houtput = NULL;//其本质是一个指针，可以初始化为NULL
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);//-》返回标准输出设备的句柄
	//参数中可以传递三种宏，
	//分别为STD_INPUT_HANDLE标准输入设备（如键盘），
	//STD_OUTPUT_HANDLE标准输出设备（如控制台窗口）
	//及STD_ERROR_HANDLE标准错误设备

/*光标信息的结构体
typedef struct _CONSOLE_CURSOR_INFO {
	DWORD dwSize;//光标百分比
	BOOL bVisible;//光标可见性
} CONSOLE_CURSOR_INFO, * PCONSOLE_CURSOR_INFO;*/
	CONSOLE_CURSOR_INFO cursor_info = { 0 };
	GetConsoleCursorInfo(houtput, &cursor_info);
	printf("%d\n", cursor_info.dwSize);//25\n->光标大小为25%
	cursor_info.dwSize = 50;//将光标信息大小改为50%
	SetConsoleCursorInfo(houtput, &cursor_info);//设置光标
	cursor_info.bVisible = false;//将光标信息改为不可见
	SetConsoleCursorInfo(houtput, &cursor_info);//设置光标
	cursor_info.bVisible = true;//将光标信息改为可见，便于后面测试
	SetConsoleCursorInfo(houtput, &cursor_info);//设置光标
	SetConsoleCursorPosition(houtput, s);//将光标位置改为s的坐标
	system("pause");
}

//7.获取按键情况的API：GetAsyncKeyState，参数为虚拟键值，该API的返回值为一个short类型数据
//若一直按住一个键没松手，该返回值的二进制的最高位（第15位）就是1，若刚刚（极短时间内）完整的按过一次对应按键，
//该返回值的二进制的最低位（第0位）就是1可以判断从调用该API之前的一小段时间内是否按过对应按键
//也就是说，通过该API的返回值可以实现两种判断，一是可以通过15位判断是否持续在按，二是可以通过最低位判断是否刚刚按过
//（注：虚拟键值类似ASCII值的功能，只不过虚拟键值代表的是按键/鼠标，如VK_LBUTTON 0x01 鼠标左键）
#define KEY_PRESS(VK) ((GetAsyncKeyState(VK) & 1) ? 1 : 0)//可直接将GetAsyncKeyState(VK_BACK)写为宏，便于使用
void test3()
{
	//直接使用该API对其按下瞬间的行为进行测试，
	//结果是需要在程序运行的瞬间按下空格，否则就会输出else
	//short ret = GetAsyncKeyState(VK_SPACE);//可以使用short接收GetAsyncKeyState(VK_BACK)的返回值，便于后续直接使用进行判断
	//while (1)
	//{
	//	if (ret & 1 == 1)
	//	{
	//		printf("按下了空格！\n");
	//	}
	//	else {
	//		printf("未按下空格！\n");
	//	}
	//}
	
	//使用死循环对该API的按下瞬间的行为进行测试，结果是，
	//按下空格的一瞬间会输出按下了空格！其余时间输出未按下空格！
	//-》该API检测的按键状态不会在瞬间中因二次调用而清除
	//while (1)
	//{
	//	if (KEY_PRESS(VK_SPACE))
	//	{
	//		printf("按下了空格！\n");
	//	}
	//	else {
	//		printf("未按下空格！\n");
	//	}
	//	Sleep(100);//睡眠，便于看到输出
	//}

	//尝试对该API一直按键不松手的行为的测试，结果是按住不松手就一直打印 按下了空格！
	//一但松手就打印 未按下空格！
	while (1)
	{
		if(GetAsyncKeyState(VK_SPACE) & (1 << 15))
		{
			printf("按下了空格！\n");
		}
		else {
			printf("未按下空格！\n");
		}
	}

}

int main()
{
	//test1();
	//test2();
	test3();
	return 0;
}